package com.bang.daybreak.common.util;

import com.bang.daybreak.common.annotation.DynamicTableField;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 生成动态表数据工具类
 *
 * @author : wdj
 * @since : 2019/6/13 0013 下午 19:42
 * @version 1.0
 */
@Slf4j
public class DynamicTableUtil {

    /**
     * 动态实现表格展示功能(在实体上通过添加注解DynamicTableField的方式实现动态表格生成.)
     *
     * @param t   实体实体类属性中需要标注注解
     *            example:@DynamicTableField(name = "zdrname", desc = "重点人名称")
     *            private String zdrname.
     *            注：该注解目前只定义应用到属性上，不可应用到方法和类。
     * @param <T> String
     * @return
     */
    public static <T> List<Map<String, Object>> dynamicTablesGenerate(T t) {
        List<Map<String, Object>> dynamicTablesList = new ArrayList<>();
        if (null == t) {
            return dynamicTablesList;
        }
        // 把包含查询结果数据的实体转为map
        Map<String, Object> map = TypeUtils.objectToMap(t);
        Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
        try {
            while (iterator.hasNext()) {
                Map.Entry<String, Object> next = iterator.next();
                String key = next.getKey();
                Object value = next.getValue();

                Field field = t.getClass().getDeclaredField(key);
                field.setAccessible(true);
                // 判断该属性字段是否存在注解.
                boolean annotationPresent = field.isAnnotationPresent(DynamicTableField.class);
                if (annotationPresent) {
                    // 通过反射获取到该属性字段上标注该注解的字段.
                    DynamicTableField dynamicTableField = field.getDeclaredAnnotation(DynamicTableField.class);
                    // 把动态表格信息保存.
                    Map<String, Object> dtgMap = new HashMap<>();
                    dtgMap.put("tableField", key);
                    dtgMap.put("tableFieldValue", value);
                    dtgMap.put("tableFieldDesc", dynamicTableField.desc());
                    dynamicTablesList.add(dtgMap);
                }
            }
        } catch (Exception e) {
            log.error("解析动态表格展示出错.{}", e.getMessage());
        }
        return dynamicTablesList;
    }

    /**
     * 动态实现表格展示功能(非注解方式实现，表格表头描述信息通过在实体类m中定义属性字段来实现)
     *
     * @param t   生成的实体
     * @param m   动态表头  example: 实体类M中定义属性 public static final String ZDRNAME = "重点人姓名";
     *            对应实体t中的属性private String zdrname.
     * @param <T> String
     * @param <M> Object
     * @return
     */
    public static <T, M> List<Map<String, Object>> dynamicTablesGenerate(T t, M m) {
        List<Map<String, Object>> dynamicTablesList = new ArrayList<>();
        // 把包含查询结果数据的实体转为map
        Map<String, Object> map = TypeUtils.objectToMap(t);
        Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> next = iterator.next();
            String key = next.getKey();
            Object value = next.getValue();
            try {
                // 把包含查询结果数据key转表字段
                String tableField = StringUtil.humpToUnderscore(key);
                // 把包含查询结果数据的字段跟动态表头实体类字段对比，当相同的时候得到该字段属性值，即定义的字段说明
                Field declaredField = m.getClass().getDeclaredField(tableField.toUpperCase());
                declaredField.setAccessible(true);
                Object tableFieldDesc = declaredField.get(m);
                Map<String, Object> dtgMap = new HashMap<>();
                dtgMap.put("tableField", key);
                dtgMap.put("tableFieldValue", value);
                dtgMap.put("tableFieldDesc", tableFieldDesc);
                dynamicTablesList.add(dtgMap);
            } catch (NoSuchFieldException e) {
                log.error("反射获取类的属性出错[{}]", e.getMessage());
            } catch (IllegalAccessException e) {
                log.error("反射获取类的私有属性出出错，declaredField.setAccessible(true)对私有字段访问取消权限检查[{}]", e.getMessage());
            }

        }
        return dynamicTablesList;
    }

}
